package com.youlu.campus.web.data.service.impl;

import com.youlu.campus.base.common.Constants;

import com.youlu.campus.web.data.entity.DayUserStatistics;
import com.youlu.campus.web.data.entity.SystemData;
import com.youlu.campus.web.data.service.DayUserStatisticsService;
import com.youlu.campus.web.common.utils.DateTimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class DayUserStatisticsServiceImpl implements DayUserStatisticsService {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private MongoTemplate mongoTemplate;
    private final Long keyExpire = 24 * 60 * 60L;

    @Override
    @Async
    public void accumulationDau(String tenantId, String userId) {
        log.info(":>>> 开始累加租户:{},用户:{} DAU", tenantId, userId);
        String key = this.getDauRedisKey(tenantId);
        try {
            // TODO:RedisTemplate 序列化方式可能存在问题
            Long count = redisTemplate.opsForValue().increment(key, 1L);
            if (count.compareTo(0L) == 1) {
                redisTemplate.expire(key, keyExpire, TimeUnit.SECONDS);
                log.debug(":>>> 设置key:{} 过期时间24小时之后 ", key);
            }
            this.updateAccumulationDau(tenantId);
        } catch (Exception e) {
            log.error(":>>> 设置租户:{} 的DAU错误:{}", e);

        }

    }

    @Override
    @Async
    public void accumulationNewUser(String tenantId, String userId) {
        log.info(":>>> 开始累加租户:{},用户:{} 新用户数", tenantId, userId);
        String key = this.getNewUserRedisKey(tenantId);
        try {
            // TODO:RedisTemplate 序列化方式可能存在问题
            Long count = redisTemplate.opsForValue().increment(key, 1L);
            if (count.compareTo(0L) == 1) {
                redisTemplate.expire(key, keyExpire, TimeUnit.SECONDS);
                log.debug(":>>> 设置key:{} 过期时间24小时之后 ", key);
            }
            this.updateAccumulationNewUser(tenantId);
        } catch (Exception e) {
            log.error(":>>> 设置租户:{} 的DAU错误:{}", e);

        }

    }

    @Override
    @Async
    public void accumulationAllUser(String tenantId, String userId) {
        log.info(":>>> 开始累加租户:{},所有用户:{} 用户总数", tenantId, userId);
        String key = this.getAllUserRedisKey(tenantId);
        try {
            // TODO:RedisTemplate 序列化方式可能存在问题
            Long count = redisTemplate.opsForValue().increment(key, 1L);
            this.updateAccumulationAllUser(tenantId);
        } catch (Exception e) {
            log.error(":>>> 设置租户:{} 的DAU错误:{}", e);

        }

    }


    /**
     * 获取当天0点时间，需要服务器时统服务器
     *
     * @return
     */
    private String getDay0() {
        Date zero = this.getDay0Date();
        //格式化日期
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //转为字符串
        String dateStr = s.format(zero);
        return dateStr;

    }

    private Date getDay0Date() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date zero = calendar.getTime();
        return zero;

    }

    protected String getDauRedisKey(String tenantId) {
        String key = String.format(Constants.SYSTEM_USER_COUNTER_ID_DAU_RPEFIX, tenantId, this.getDay0());
        log.info(":>>> 租户:{} DAU的Redis Key:{}", tenantId, key);
        return key;
    }

    protected String getNewUserRedisKey(String tenantId) {
        String key = String.format(Constants.SYSTEM_USER_COUNTER_ID_NEW_USER_RPEFIX, tenantId, this.getDay0());
        log.info(":>>> 租户:{} 新用户的Redis Key:{}", tenantId, key);
        return key;
    }

    protected String getAllUserRedisKey(String tenantId) {
        String key = String.format(Constants.SYSTEM_USER_COUNTER_ID_ALL_USER_RPEFIX, tenantId);
        log.info(":>>> 租户:{} 所有用户的Redis Key:{}", tenantId, key);
        return key;
    }

        private void updateAccumulationDau(String tenantId) {
        Query query = new Query();
        Date startTime = this.getDay0Date();
        Criteria criteria = new Criteria().andOperator(Criteria.where("statisticsTime").gte(DateTimeUtils.dateToISODate(startTime)), Criteria.where("statisticsTime").lte(DateTimeUtils.dateToISODate(new Date(startTime.getTime() + 24 * 60 * 60 * 1000L))));
        query.addCriteria(criteria);
        DayUserStatistics dayUserStatistics = mongoTemplate.findOne(query, DayUserStatistics.class);
        if (Objects.isNull(dayUserStatistics)) {
            dayUserStatistics = new DayUserStatistics();
            dayUserStatistics.setDau(1);
            dayUserStatistics.setCreatedTime(new Date());
            dayUserStatistics.setDeleted(Boolean.FALSE);
            dayUserStatistics.setTenantId(tenantId);
            dayUserStatistics.setStatisticsTime(startTime);
            mongoTemplate.insert(dayUserStatistics);
            log.info(":>>> 租户:{} DAU:{} 统计不存在,新增", tenantId, startTime);
            return;
        }
        Update update = new Update();
        update.inc("dau", 1);
        Query query1 = new Query();
        query1.addCriteria(Criteria.where("id").is(dayUserStatistics.getId()));
        mongoTemplate.updateFirst(query1, update, DayUserStatistics.class);


    }

        private void updateAccumulationNewUser(String tenantId) {
        Query query = new Query();
        Date startTime = this.getDay0Date();
        Criteria criteria = new Criteria().andOperator(Criteria.where("statisticsTime").gte(DateTimeUtils.dateToISODate(startTime)), Criteria.where("statisticsTime").lte(DateTimeUtils.dateToISODate(new Date(startTime.getTime() + 24 * 60 * 60 * 1000L))));
        query.addCriteria(criteria);
        DayUserStatistics dayUserStatistics = mongoTemplate.findOne(query, DayUserStatistics.class);
        if (Objects.isNull(dayUserStatistics)) {
            dayUserStatistics = new DayUserStatistics();
            dayUserStatistics.setNewUser(1);
            dayUserStatistics.setCreatedTime(new Date());
            dayUserStatistics.setDeleted(Boolean.FALSE);
            dayUserStatistics.setTenantId(tenantId);
            dayUserStatistics.setStatisticsTime(startTime);
            mongoTemplate.insert(dayUserStatistics);
            log.info(":>>> 租户:{} 新用户:{} 统计不存在,新增", tenantId, startTime);
            return;
        }
        Update update = new Update();
        update.inc("newUser", 1);
        Query query1 = new Query();
        query1.addCriteria(Criteria.where("id").is(dayUserStatistics.getId()));
        mongoTemplate.updateFirst(query1, update, DayUserStatistics.class);


    }

        private void updateAccumulationAllUser(String tenantId) {
        Query query = new Query().addCriteria(Criteria.where("tenantId").is(tenantId));
        SystemData systemData = mongoTemplate.findOne(query, SystemData.class);
        if (Objects.isNull(systemData)) {
            systemData = new SystemData();
            systemData.setTotalUser(1L);
            systemData.setCreatedTime(new Date());
            mongoTemplate.insert(systemData);
            log.info(":>>> 租户:{} 所有用户 统计不存在,新增", tenantId);
            return;
        }
        Update update = new Update();
        update.inc("totalUser", 1);
        Query query1 = new Query();
        query1.addCriteria(Criteria.where("id").is(systemData.getId()));
        mongoTemplate.updateFirst(query1, update, SystemData.class);


    }
}
